package ch.trackedbean.client.views;

import static ch.trackedbean.client.resources.Messages.*;
import java.awt.*;
import java.awt.event.*;
import java.util.List;
import javax.swing.*;
import ch.trackedbean.binding.action.*;
import ch.trackedbean.binding.components.*;
import ch.trackedbean.binding.mapping.*;
import ch.trackedbean.binding.util.*;
import ch.trackedbean.client.*;
import ch.trackedbean.client.gui.*;
import ch.trackedbean.server.data.dom.*;
import ch.trackedbean.server.data.to.*;
import ch.trackedbean.tracking.*;

/**
 * Panel displaying an {@link PersonTO}.
 * 
 * @author hautle
 */
@SuppressWarnings("serial")
public class PersonDetail extends DataPanel<PersonTO> {
    /** The id of the action showing this detail. */
    public static final String DETAIL_ACTION_ID = PersonDetail.class.getName();

    /** Table showing the addresses of the person. */
    private TablePanel<AddressTO> addresses = new TablePanel<AddressTO>(false, true);

    /** Action to remove the selected addresses. */
    private DeleteAddressAction deleteAddress = new DeleteAddressAction();

    /** Action to add a address. */
    private AbstractListDependentAction<AddressTO> addAddress = new AbstractListDependentAction<AddressTO>("Add address") {
        @Override
        public boolean listChanged(List<AddressTO> list) {
            return list != null && list.size() < 3;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            final List<AddressTO> ad = getModel().getAddresses();
            ad.add(new AddressTO());
        }
    };

    /**
     * Default constructor.
     */
    public PersonDetail() {
        super(false);
        init();
        initTable();
    }

    /**
     * Initializes the gui.
     */
    private void init() {
        setLayout(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        c.insets.set(5, 2, 5, 2);
        c.anchor = GridBagConstraints.NORTHWEST;
        c.gridx = 0;
        c.gridy = 0;
        addTextField(PersonTO.ATTR_NAME, NAME, c);
        c.gridy++;
        addTextField(PersonTO.ATTR_FIRST_NAME, FIRST_NAME, c);
        c.gridy++;
        addTextField(PersonTO.ATTR_AGE, AGE, c);
        c.gridy++;
        c.gridx = 0;
        add(new JButton(addAddress), c);
        c.gridy++;
        c.gridx = 0;
        add(new JButton(deleteAddress), c);
        c.gridy++;
        c.gridx = 0;
        c.gridwidth = 3;
        c.weightx = 1;
        c.weighty = 1;
        c.fill = GridBagConstraints.BOTH;
        add(addresses, c);
        c.gridy++;
        c.weighty = 0;
        c.fill = GridBagConstraints.HORIZONTAL;
        add(createButtonPanel(), c);
        getMapping().createTableBinding(PersonTO.ATTR_ADDRESSES, addresses.getMapping());
    }

    /**
     * Creates the button panel.
     * 
     * @return The panel
     */
    private JPanel createButtonPanel() {
        final JPanel p = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        final SaveAction save = new SaveAction();
        getMapping().createStatusDependentBinding(IBeanStatus.BEAN_STRUCTURE_STATUS, save);
        p.add(new JButton(save));
        return p;
    }

    /**
     * Configures the address table.
     */
    private void initTable() {
        new TableSelectionActionHandler<AddressTO>(addresses.getMapping()).addAction(deleteAddress);
        getMapping().createDependentElementBinding(PersonTO.ATTR_ADDRESSES, deleteAddress);
        getMapping().createDependentElementBinding(PersonTO.ATTR_ADDRESSES, addAddress);
        addresses.addColumn(ADDRESS_STREET, AddressTO.ATTR_STREET);
        addresses.addColumn(ADDRESS_STREET_NR, AddressTO.ATTR_STREET_NUMBER);
        addresses.addComboBoxColumn(ADDRESS_CITY, AddressTO.ATTR_PLACE, "${" + PlaceDom.ATTR_CITY + "}", PlaceDom.class, null, null);
        addresses.addComboBoxColumn(ADDRESS_COUNTRY, AddressTO.ATTR_COUNTRY, "${" + CountryDom.ATTR_NAME + "}", CountryDom.class, null, null);
    }

    /**
     * Adds a textfield.
     * 
     * @param attribute The property name
     * @param label The label
     * @param c {@link GridBagConstraints} to use
     */
    private void addTextField(String attribute, String label, GridBagConstraints c) {
        c.gridx = 0;
        add(getMapping().createStatusDependentBinding(attribute, new StatusLabel(label)), c);
        c.gridx++;
        final JTextField field = new JTextField(10);
        field.setMinimumSize(field.getPreferredSize());
        add(attribute, field, c);
    }

    /**
     * The action to save the changes.
     * 
     * @author hautle
     */
    public class SaveAction extends ServerAction<PersonTO, Void, Void> implements IStatusDependent {
        /**
         * Default constructor.
         */
        public SaveAction() {
            super("Save");
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected String getProgressBarText() {
            return "Saving...";
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public Void perform(ActionEvent e, Void prepared, List<PersonTO> selection) throws Exception {
            ServerAccess.ME.getSrv().savePerson(getModel());
            return null;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected void finishHook(ActionEvent e, Void prepare, Void result, List<PersonTO> selection) {
            MainFrame.ME.disposeWindow(PersonDetail.this);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void setStatus(Status status) {
            setEnabled(status.getFlag() == BeanStatusFlag.CHANGED);
        }
    }

    /**
     * Action to delete addresses.
     * 
     * @author hautle
     */
    private class DeleteAddressAction extends AbstractListDependentAction<AddressTO> implements ISelectionAction<AddressTO> {
        /** Selection holder. */
        private SelectionHolder<AddressTO> selection = new SelectionHolder<AddressTO>();

        /**
         * Default constructor.
         */
        public DeleteAddressAction() {
            super("Delete");
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public boolean listChanged(List<AddressTO> list) {
            return list != null && list.size() > 1 && !selection.get().isEmpty();
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public String getActionID() {
            return DeleteAddressAction.class.getName();
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public boolean selectionChanged(List<AddressTO> selection) {
            this.selection.set(selection);
            return listChanged(getList());
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void actionPerformed(ActionEvent e) {
            final List<AddressTO> list = getModel().getAddresses();
            for (AddressTO t : selection.get())
                list.remove(t);
        }
    }
}
